note
	description: "[
					Representation of a basic {US_PHONE_VALIDATOR}, which
					validates raw 10 digit {US_PHONE}.number's in various forms.
					
					1. Area codes start with a number from 2-9, followed by 0-8, 
						and then any third digit.
					2. The second group of three digits, known as the central office 
						or exchange code, starts with a number from 2-9, followed by 
						any two digits.
					3. The final four digits, known as the station code, have no restrictions.
					]"
	date: "$Date: $"
	revision: "$Revision: $"

class
	US_PHONE_VALIDATOR 

inherit
	PHONE_VALIDATOR

feature -- Access

	invalid_message (a_number: attached like {US_PHONE}.number): STRING
			-- <Precursor>
		do
			create Result.make_empty
			if not is_valid (a_number) then
				Result.append (Invalid_number_message)
			end
			if not is_valid_area_code (a_number) then
				Result.append (Invalid_area_code_message)
			end
			if not is_valid_exchange (a_number) then
				Result.append (Invalid_exchange_code_message)
			end
			if not is_valid_station_code (a_number) then
				Result.append (Invalid_station_code_message)
			end
		end

feature -- Status Report

	is_valid (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		do
			Result := is_digits (a_number) and
						(a_number.count.is_equal (10) or a_number.count.is_equal (5) or a_number.count.is_equal (3)) and
						is_valid_area_code (a_number) and
						is_valid_exchange (a_number)
		end

	is_digits (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- Is `a_number' all digits?
		do
			Result := across a_number as al_digit all al_digit.item.is_digit end
		end

	is_valid_area_code (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- Does `a_number' have a valid area code in the first three digits?
			-- Area codes start with a number from 2-9, followed by 0-8,
			--	and then any third digit. So, digit 1 is not 0 or 1 and digit 2
			--  is not 9.
		require
			all_digits: is_digits (a_number)
		do
			Result :=
				(not a_number.substring (1, 1).is_equal ({US_PHONE}.check_digit_0) and not a_number.substring (1, 1).is_equal ({US_PHONE}.check_digit_1)) and
					not a_number.substring (2, 2).is_equal ({US_PHONE}.check_digit_9)
		end

	is_valid_exchange, is_valid_central_office (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- Does `a_number' have a valid exchange|central office number?
			--| The second group of three digits, known as the central office
			--| 	or exchange code, starts with a number from 2-9, followed by
			--| 	any two digits. Reciprocally, does not start with 0 or 1.
		require
			all_digits: is_digits (a_number)
		do
			if attached {STRING} a_number.substring (4, 4) as al_digit then
				Result := (not al_digit.is_equal ({US_PHONE}.check_digit_0)) and
							(not al_digit.is_equal ({US_PHONE}.check_digit_1))
			end
		end

	is_valid_subscriber_number, is_valid_station_code (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- Does `a_number' have a valid station code?
		require
			all_digits: is_digits (a_number)
		do
			if attached {STRING} a_number.substring (7, 10) as al_substring then
				Result := across al_substring as al_station_code all al_station_code.item.is_digit end
			end
		end

	is_ficticious (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		local
			l_comparitor: STRING
		do
			l_comparitor := "000"
			if attached {STRING} a_number as al_number then
				inspect a_number.count
				when 10 then
					l_comparitor := al_number.substring (4, 6)
				when 7 then
					l_comparitor := al_number.substring (1, 3)
				end
			end
			Result := l_comparitor.same_string (Ficticious_exchange)
		end

	is_directory_assistance (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		do
			if attached {STRING} a_number as al_number then
				Result := al_number.count = 7 and al_number.same_string (Directory_assistance)
			end
		end

	is_information (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		do
			if attached {STRING} a_number as al_number then
				Result := al_number.count = 3 and al_number.same_string (Information_number)
			end
		end

	is_emergency (a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		do
			if attached {STRING} a_number as al_number then
				Result := al_number.count = 3 and al_number.same_string (Emergency_number)
			end
		end

	is_system_services	(a_number: attached like {US_PHONE}.number): BOOLEAN
			-- <Precursor>
		do
			if attached {STRING} a_number as al_number then
				Result := al_number.count = 3 and al_number.same_string (System_services)
			end
		end

feature {TEST_SET_HELPER} -- Constants

	Emergency_number: STRING = "911"

	Information_number: STRING = "411"

	Directory_assistance: STRING = "5551212"

	Ficticious_exchange: STRING = "555"

	System_services: STRING = "611"

	Invalid_number_message: STRING = "Phone number is invalid due to:%N"

	Invalid_area_code_message: STRING = "Invalid area code with a 0 or 1 as the first digit or 9 as the second%N"

	Invalid_exchange_code_message: STRING = "Invalid exchange or central office code with a 0 or 1 as the first digit%N"

	Invalid_number_of_digits_message: STRING = "Number must be 10 digits only%N"

	Invalid_station_code_message: STRING = "Station code is not all digits%N"

note
	copyright: "Copyright (c) 2012-2012, Greater Atlanta User Group for Eiffel (GAUGE)"
	license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
	licensing_options: "http://www.eiffel.com/licensing"
	copying: "[
			This file is part of the Greater Atlanta User Group for Eiffel (GAUGE), Eiffel Development Environment.
			
			GAUGE's Eiffel Development Environment is free
			software; you can redistribute it and/or modify it under
			the terms of the GNU General Public License as published
			by the Free Software Foundation, version 2 of the License
			(available at the URL listed under "license" above).
			
			GAUGE's Eiffel Development Environment is
			distributed in the hope that it will be useful, but
			WITHOUT ANY WARRANTY; without even the implied warranty
			of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
			See the GNU General Public License for more details.
			
			You should have received a copy of the GNU General Public
			License along with Eiffel Software's Eiffel Development
			Environment; if not, write to the Free Software Foundation,
			Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
		]"
	source: "[
			GAUGE
			Atlanta, GA
			Website http://www.atlantausergroups.com/group/gauge
		]"
end
